package com.example.demo.ImgTest;

import com.example.demo.common.exception.BaseException;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;

/**
 *
 * @author FF998
 */
public class ZhuanHuan {

    public static void main(String[] args) throws Exception {

        // 合成的MP4 存放的地址路径 这里的路径并不会自动创建,需要手动提前创建好,否则会报错:Could not open 'null'
        // 图片存放的地址路径
//        String imgUrl = "D:\\upload_files\\yanhai\\assets\\VideoFile\\SYQM1\\img";
        String imgUrl = "D:\\upload_files\\yanhai\\assets\\VideoFile\\SYGCD1\\img";
        // 合成视频存放地址
//        String mp4SavePath = "D:\\upload_files\\yanhai\\assets\\VideoFile\\SYQM1\\video\\qmProductVideo1.mp4";
        String mp4SavePath = "D:\\upload_files\\yanhai\\assets\\VideoFile\\SYGCD1\\video\\gcdProductVideo1.mp4";

        // 视频后缀
        String videoSuffix = "mp4";
//        String videoSuffix = "flv";
        // 视频时长
        int totalTime = 30;
        int width = 2560;
        int height = 1440;

        //读取所有图片
        File file = new File(imgUrl);
        File[] fileList = file.listFiles();

        // 使用自定义比较器按文件名排序
        Arrays.sort(fileList, Comparator.comparingInt(x -> {
            try {
                return Integer.parseInt(x.getName().replaceAll("[^0-9]", ""));
            } catch (NumberFormatException e) {
                return -1; // 如果文件名不是有效的数字，则将其视为负数
            }
        }));

        createMp4(totalTime, videoSuffix, mp4SavePath, fileList, width, height);
    }

    private static void createMp4(int totalTime, String videoSuffix, String mp4SavePath, File[] fileList, int width, int height) throws FrameRecorder.Exception, BaseException {
        //视频宽高最好是按照常见的视频的宽高  16：9  或者 9：16
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(mp4SavePath, width, height);
        // 设置视频编码层模式
        // import org.bytedeco.ffmpeg.global.avcodec;可能需要手动复制添加
        // flv:avcodec.AV_CODEC_ID_FLV1;
        // mp4(清晰,但浏览器不支持):avcodec.AV_CODEC_ID_MPEG4;
        // 3gp:avcodec.AV_CODEC_ID_H263;
        // avi:avcodec.AV_CODEC_ID_HUFFYUV;
        // 通用但失帧:avcodec.AV_CODEC_ID_H264
//      recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4);
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        recorder.setFormat(videoSuffix);
        // 默认:400000 但使用AV_CODEC_ID_H264,会模糊,所以设置比特率为 5 Mbps,但是视频文件会很大,且生成速度会变慢
        recorder.setVideoBitrate(5000000);
        // 设置视频图像数据格式
        // 可能需要手动复制添加
        // import org.bytedeco.ffmpeg.global.avutil;
        recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);

        // 计算公式:视频时长 = 图片总数 / 帧率

        int frameRate = fileList.length / totalTime;
        // 帧率公式: 帧率 = 图片总数 / 视频的总时长（单位可以是秒或毫秒 当前:秒）;

        // 设置视频为x帧每秒(每秒x张图片)
        recorder.setFrameRate(frameRate);
        recorder.start();

        try {
            // Java 2D帧转换器
            Java2DFrameConverter converter = new Java2DFrameConverter();
            // 录制一个30秒的视频,30秒为自定义的一个视频时间长度,图片少则在30秒内,多则到30秒停止
            // 图片总量
            for (File file : fileList) {
                BufferedImage read = ImageIO.read(file);
                // 每张图片 记录一次
                recorder.record(converter.getFrame(read));
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("合成视频失败!");
        } finally {
            //最后一定要结束并释放资源
            recorder.stop();
            recorder.release();
        }
    }

    public static boolean mergeAudioAndVideo(String videoPath, String audioPath, String outPut) throws Exception {
        boolean isCreated = false;

        isCreated = true;
        File file = new File(videoPath);
        if (!file.exists()) {
            return false;
        }
        FrameRecorder recorder = null;
        FrameGrabber grabber1 = null;
        FrameGrabber grabber2 = null;
        try {
            //抓取视频帧
            grabber1 = new FFmpegFrameGrabber(videoPath);
            //抓取音频帧
            grabber2 = new FFmpegFrameGrabber(audioPath);
            grabber1.start();
            grabber2.start();
            //创建录制
            recorder = new FFmpegFrameRecorder(outPut,
                    grabber1.getImageWidth(), grabber1.getImageHeight(),
                    grabber2.getAudioChannels());

            recorder.setFormat("mp4");
            recorder.setFrameRate(grabber1.getFrameRate());
            recorder.setSampleRate(grabber2.getSampleRate());
            recorder.start();

            Frame frame1;
            Frame frame2;

            //先录入视频
            while ((frame1 = grabber1.grabFrame()) != null) {
                recorder.record(frame1);
            }
            //然后录入音频
            while ((frame2 = grabber2.grabFrame()) != null) {
                recorder.record(frame2);
            }
            grabber1.stop();
            grabber2.stop();
            recorder.stop();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (recorder != null) {
                    recorder.release();
                }
                if (grabber1 != null) {
                    grabber1.release();
                }
                if (grabber2 != null) {
                    grabber2.release();
                }
            } catch (FrameRecorder.Exception e) {
                e.printStackTrace();
            }
        }

        return isCreated;

    }

}

